package com.freeter.XMLUtil;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.freeter.model.xml.Address;
import com.freeter.model.xml.Person;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

public class XmlUtil {

	public static String xmlFile = "xmlfile";

	public static void main(String[] args)
			throws Exception

	{
		String root = Thread.currentThread().getContextClassLoader().getResource(xmlFile).getPath();
		/*
		 * String res=toXML(); toEntity(res);
		 */
		Map mp = new HashMap();
		Map nestedMap = new HashMap();
		Map nestedNestedMap = new HashMap();

		// Map contains: EmpId,Name
		mp.put("name", "Deepak kumar modi");
		mp.put("password", "Sweep panorama");
		mp.put("salt", "HD Video");
		mp.put("dateTime", "My Motorola Mobile");
		// System.out.println(mp);

		/*
		 * // nestedMap contains: FirstName, LastName nestedMap.put("Deepak",
		 * "Modi"); nestedMap.put("Sweep", "panorama");
		 * 
		 * // NestedNestedMap contains: FN,Name nestedNestedMap.put("FN",
		 * "DEEPAK"); nestedNestedMap.put("Object", "123");
		 * 
		 * nestedMap.put("smap", nestedNestedMap);
		 * 
		 * mp.put("123", nestedMap);
		 */

		/*
		 * XStream magicApi = new XStream(new DomDriver());
		 * 
		 * magicApi.alias("root", Map.class); magicApi.registerConverter(new
		 * MapEntryConverter());
		 * 
		 * String xml = magicApi.toXML(mp);
		 * System.out.println("Result of newly formed XML:");
		 * System.out.println(xml); toEntity(xml);
		 */

		System.out.println(mapToXml(mp));
		;
		Person person = new Person();
		person.setName("huyun");
		person.setPhoneNuber(1385546);
		Address address1 = new Address();
		address1.setHouseNo(888);
		address1.setStreet("newyork");
		Address address2 = new Address();
		address2.setHouseNo(45645);
		address2.setStreet("丰台");
		person.getAddresses().add(address1);
		person.getAddresses().add(address2);
		String pxml = toXML(person);
		System.out.println(pxml);
		Person p = toEntity(pxml, Person.class);
		System.out.println(p);

		toXMLFile(person, root + "/data.xml");
		Person p2 = toBeanFromFile(root+"/", "data.xml", Person.class);
		System.out.println(p2);
	}

	public static <T> T toEntity(String inputXML, Class<T> cls)
			throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
		XStream xs = new XStream();
		// 这句和@XStreamAlias("person")等效
		// xs.alias("person",Person.class);
		// xs.alias("address",Address.class);
		// xs.setMode(XStream.NO_REFERENCES);
		// 这句和@XStreamImplicit()等效
		// xs.addImplicitCollection(Person.class,"addresses");
		// 这句和@XStreamAsAttribute()
		// xs.useAttributeFor(Person.class, "name");
		// 注册使用了注解的VO
		xs.processAnnotations(cls);
		T obj = (T) xs.fromXML(inputXML);
		return obj;

	}

	public static String toXML(Object obj) {
		XStream xstream = new XStream();

		xstream.processAnnotations(obj.getClass()); // 通过注解方式的，一定要有这句话

		return xstream.toXML(obj);
	}

	/*
	 * PrintWriter无追加模式，若写入已有文件，将清空原文件，重新写入；
	 */
	public static void toXMLFile(Object obj, String path) throws Exception {
		XStream xstream = new XStream();

		xstream.processAnnotations(obj.getClass()); // 通过注解方式的，一定要有这句话
		PrintWriter pw = new PrintWriter(path, "utf-8");
		xstream.toXML(obj, pw);
	}

	public static String mapToXml(Map map) {
		XStream xstream = new XStream();
		xstream.alias("xml", Map.class);
		xstream.registerConverter(new MapEntryConverter());
		String xml = xstream.toXML(map);
		 
		return xml;
	}

	public static class MapEntryConverter implements Converter {
		public boolean canConvert(Class clazz) {
			return AbstractMap.class.isAssignableFrom(clazz);
		}

		public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
			AbstractMap map = (AbstractMap) value;
			for (Object obj : map.entrySet()) {
				Entry entry = (Entry) obj;
				writer.startNode(entry.getKey().toString());
				writer.setValue(entry.getValue().toString());
				writer.endNode();
			}
		}

		public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
			Map<String, String> map = new HashMap<String, String>();
			while (reader.hasMoreChildren()) {
				reader.moveDown();
				map.put(reader.getNodeName(), reader.getValue());
				reader.moveUp();
			}
			return map;
		}
	}

	/**
	 * 从xml文件读取报文
	 * 
	 * @Title: toBeanFromFile
	 * @Description: TODO
	 * @param absPath
	 *            绝对路径
	 * @param fileName
	 *            文件名
	 * @param cls
	 * @throws Exception
	 * @return T
	 */
	public static <T> T toBeanFromFile(String absPath, String fileName, Class<T> cls) throws Exception {
		String filePath = absPath + fileName;
		InputStream ins = null;
		try {
			ins = new FileInputStream(new File(filePath));
		} catch (Exception e) {
			throw new Exception("读{" + filePath + "}文件失败！", e);
		}

		XStream xstream = new XStream();
		xstream.processAnnotations(cls);
		T obj = null;
		try {
			obj = (T) xstream.fromXML(ins);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new Exception("解析{" + filePath + "}文件失败！", e);
		}
		if (ins != null)
			ins.close();
		return obj;
	}

}
